package club.kingyin.easycache.key;

import club.kingyin.easycache.exception.MethodArgsException;
import club.kingyin.easycache.method.CacheMethod;
import club.kingyin.easycache.utils.AnnotationUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.DefaultParameterNameDiscoverer;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 主要的EasyCacheKey，定制自定义Key生成方式需要继承此类
 *
 */
@Slf4j
public class MethodEasyCacheKey extends AbstractEasyCacheKey {
    @Override
    protected void setPrams() {
    }

    public MethodEasyCacheKey() {

    }

    public MethodEasyCacheKey(String module, Method method, Object... args) {
        this.module = module;
        addByMethodAndArgs(method,args);
    }

    private boolean checkArgsLength(String[] names, Object[] args) {
        if (names == null && args == null)
            return true;
        assert names != null;
        return names.length == args.length;
    }

    private void init() {
        if (getPostProcesses() == null) {
            // 默认装配inject处理器
            AnnotationUtils.registerAnnotationHandler(this);
        }
    }

    // 代理调用时候生成EasyCacheKey
    private void addByMethodAndArgs(Method method, Object...args) {
        init();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
        String[] parameterNames = discover.getParameterNames(method);
        String methodName = method.getName();
        if (!checkArgsLength(parameterNames,args)) throw new MethodArgsException("'"+methodName+"' 方法参数不匹配");
        this.methodName = methodName;
        // 预先解析原始方法参数
        for (int i = 0; i < args.length; i++) {
            prams.put(parameterNames[i],args[i]);
        }
        log.debug("模块：[{}] 方法：[{}] 原始参数注入 {}", module, methodName, Arrays.toString(parameterNames));
        // 执行注解解析操作
        for (int i = 0; i < args.length; i++) {
            if(parameterAnnotations[i].length == 0) {
                continue;
            }
            try {
                injectionParameter(parameterNames[i], args[i], parameterAnnotations[i]);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    public static class Builder {
        private Method method;
        private Object[] args;
        private String module = DEFAULT_MODULE;

        public Builder setMethod(Method method) {
            this.method = method;
            return this;
        }

        public Builder setArgs(Object[] args) {
            this.args = args;
            return this;
        }


        public Builder setModule(String module) {
            this.module = module;
            return this;
        }

        public EasyCacheKey build(CacheMethod methodInvocation, String module) {
            return new MethodEasyCacheKey(module,methodInvocation.getMethod(),methodInvocation.getArguments());
        }

        public EasyCacheKey build(CacheMethod methodInvocation) {
            return new MethodEasyCacheKey(module,methodInvocation.getMethod(),methodInvocation.getArguments());
        }

        public EasyCacheKey build() {
            return new MethodEasyCacheKey(module,method,args);
        }
    }
}
